package com.cx.common.utils;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.collection.SynchronizedCollection;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;

import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 集合工具类
 *
 * @Author:cxy
 * @Date:2019/10/24 15:11
 */
public class CollectionsUtils extends org.apache.commons.collections.CollectionUtils {

    /**
     * collection 是否 全部包含 array
     *
     * @param collection
     * @param array
     * @return
     */
    public static <T> boolean containsAll(Collection<T> collection, T[] array) {
        Set<Object> collection1 = New.hashSet(array.length);
        CollectionsUtils.addAll(collection1, array);
        return collection.containsAll(collection1);
    }

    /**
     * collection 和 array 是否完全一样
     *
     * @param collection
     * @param array
     * @return
     */
    public static <T> boolean isSame(Collection<T> collection, T[] array) {
        Set<Object> collection1 = New.hashSet(array.length);
        CollectionsUtils.addAll(collection1, array);
        return collection.containsAll(collection1) && collection1.containsAll(collection);
    }

    @SuppressWarnings("unchecked")
    public static <T> List<T> arrayList(T... args) {
        List<T> list = New.arrayList(args.length);
        addAll(list, args);
        return list;
    }

    /**
     * 两个的集合的元素是否完全相同
     *
     * @param a
     * @param b
     * @return
     */
    public static boolean isEqualAllElement(final Collection<?> a, final Collection<?> b) {
        if (a == null && b == null) {
            return true;
        }
        if ((a == null && b != null) || (a != null && b == null)) {
            return false;
        }
        if (a.containsAll(b) && b.containsAll(a)) {
            return true;
        }
        return false;
    }

    public static <T> int getSize(Collection<T> source) {
        return isEmpty(source) ? 0 : source.size();
    }

    /**
     * 获取列表的子集的拷贝
     *
     * @param <T>
     * @param source 源列表
     * @param start  开始位置
     * @param count  获取记录数量
     * @return {@link List} 返回结果是另一个 ArrayList 实例
     */
    public static <T> List<T> subListCopy(List<T> source, int start, int count) {
        if (source == null || source.size() == 0) {
            return new ArrayList<T>(0);
        }

        int fromIndex = start <= 0 ? 0 : start;
        if (start > source.size()) {
            fromIndex = source.size();
        }

        count = count <= 0 ? 0 : count; // 增加了边界处理
        int endIndex = fromIndex + count;
        if (endIndex > source.size()) {
            endIndex = source.size();
        }
        return new ArrayList<T>(source.subList(fromIndex, endIndex));
    }

    /**
     * 获取列表的子集的拷贝
     *
     * @param <T>
     * @param source     源列表
     * @param startIndex 开始位置
     * @param stopIndex  结束位置
     * @return {@link List} 返回结果是另一个 ArrayList 实例
     */
    public static <T> List<T> subList(List<T> source, int startIndex, int stopIndex) {
        if (source == null || source.size() == 0) {
            return new ArrayList<T>(0);
        }

        int fromIndex = startIndex <= 0 ? 0 : startIndex;
        if (startIndex > source.size()) {
            fromIndex = source.size();
        }

        stopIndex = stopIndex <= 0 ? 0 : stopIndex;// 增加了边界处理
        stopIndex = stopIndex <= startIndex ? startIndex : stopIndex;
        if (stopIndex > source.size()) {
            stopIndex = source.size();
        }
        return new ArrayList<T>(source.subList(fromIndex, stopIndex));
    }

    /**
     * 当列表元素不存在时，进行添加
     *
     * @param list    列表
     * @param idx     插入位置
     * @param element 插入的元素
     */
    public static <T> void addNotExist(List<T> list, int idx, T element) {
        if (!list.contains(element)) {
            list.add(idx, element);
        }
    }

    /**
     * 当列表元素不存在时，进行添加
     *
     * @param list    列表
     * @param element 插入的元素
     */
    public static <T> void addNotExist(List<T> list, T element) {
        addNotExist(list, list.size(), element);
    }

    /**
     * 删除所有
     *
     * @param list
     * @param value
     */
    public static <T> void removeValue(Collection<T> list, T value) {
        list.remove(value);
    }

    /**
     * 删除
     *
     * @param list
     * @param index
     * @return
     */
    public static <T> T remove(List<T> list, int index) {
        return list.remove(index);
    }

    /**
     * 向集合中添加元素
     *
     * @param list
     * @param value
     */
    public static <T> boolean addIfAbsent(Collection<T> list, T value) {
        boolean result = false;
        if (list instanceof CopyOnWriteArrayList) {
            result = ((CopyOnWriteArrayList<T>) list).addIfAbsent(value);
        } else if (list instanceof Set) {
            if (list instanceof SynchronizedCollection) {
                result = list.add(value);
            } else {
                synchronized (list) {
                    result = list.add(value);
                }
            }
        } else {
            synchronized (list) {
                if (!list.contains(value)) {
                    result = list.add(value);
                }
            }
        }
        return result;
    }

    /**
     * 连接集合
     *
     * @param list
     * @return
     */
    public static <T> String join(Collection<T> list) {
        String str = joinWithSeparator(list, Splitable.ATTRIBUTE_SPLIT);
        return str;
    }

    /**
     * 连接集合
     *
     * @param list
     * @return
     */
    public static <T> String joinByComma(Collection<T> list) {
        String str = joinWithSeparator(list, Splitable.COMMA);
        return str;
    }

    /**
     * 连接集合
     *
     * @param array
     * @return
     */
    public static <T> String joinArray(Collection<T> array) {
        String str = joinArrayWithSeparator(array, Splitable.ATTRIBUTE_SPLIT);
        return str;
    }

    /**
     * 连接数组
     *
     * @param array
     * @return
     */
    public static <T> String joinArrayByComma(Collection<T> array) {
        String str = joinArrayWithSeparator(array, Splitable.COMMA);
        return str;
    }

    /**
     * 特定连接符拼接
     *
     * @param list
     * @param separator
     * @return
     */
    public static <T> String joinWithSeparator(Collection<T> list, Serializable separator) {
        StringBuilder sb = StringTool.getStringBuilder();
        if (list != null) {
            for (T t : list) {
                sb.append(t).append(separator);
            }
            int length = sb.length();
            if (length > 0) {
                sb.setLength(length - 1);
            }
        }
        String value = sb.toString();
        StringTool.returnStringBuilder(sb);
        return value;
    }

    /**
     * 特定连接符拼接
     *
     * @param array
     * @param separator
     * @return
     */
    public static <T> String joinArrayWithSeparator(Collection<T> array, Serializable separator) {
        StringBuilder sb = StringTool.getStringBuilder();
        if (array != null) {
            int size = CollectionsUtils.getSize(array);
            for (int i = 0; i < size; i++) {
                sb.append(CollectionsUtils.get(array, i)).append(separator);
            }
            int length = sb.length();
            if (length > 0) {
                sb.setLength(length - 1);
            }
        }
        String value = sb.toString();
        StringTool.returnStringBuilder(sb);
        return value;
    }

    /**
     * 合并map
     *
     * @param map1
     * @param map2
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <K extends Serializable, V extends Number> Map<K, V> mergeMap(Map<K, V> map1, Map<K, V> map2) {
        if (map2 != null) {
            for (Entry<K, V> entry : map2.entrySet()) {
                K key = entry.getKey();
                V v = map1.get(key);
                if (v != null) {
                    Double value = v.doubleValue() + entry.getValue().doubleValue();
                    map1.put(key, (V) ConvertUtils.convert(value, v.getClass()));
                } else {
                    map1.put(key, entry.getValue());
                }
            }
        }
        return map1;
    }

    /**
     * @param idList
     * @return
     */
    public static <T> T findId(Collection<T> idList) {
        T id = null;
        if (idList != null && idList.size() > 0) {
            synchronized (idList) {
                Iterator<T> iterator = idList.iterator();
                if (iterator.hasNext()) {
                    id = iterator.next();
                    iterator.remove();
                }
            }
        }
        return id;
    }

    /**
     * 交换list里面两个元素的位置
     *
     * @param list
     * @param t1
     * @param t2
     * @return 是否成功
     */
    public static <T> boolean exchangePosition(List<T> list, T t1, T t2) {
        if (!list.contains(t1) || !list.contains(t2)) {
            return false;
        }
        int index1 = list.indexOf(t1);
        int index2 = list.indexOf(t2);
        list.set(index1, t2);
        list.set(index2, t1);
        return false;
    }

    /**
     * 从一个集合里随机取一个子集合 不移除源集合元素
     *
     * @param views 源集合
     * @param max   子集合的size
     * @return
     */
    public static <T> List<T> randomList(List<T> views, int max) {
        List<T> ret = new ArrayList<T>(max);
        if (isEmpty(views)) {
            return ret;
        }
        final int size = views.size();
        int index = RandomUtils.nextInt(size);
        int low = index - 1, high = index;
        while (max > 0 && (low >= 0 || high < size)) {
            if (low >= 0 && max-- > 0) {
                ret.add(views.get(low));
            }
            if (high < size && max-- > 0) {
                ret.add(views.get(high));
            }
            low--;
            high++;
        }
        return ret;
    }

    /**
     * 从一个集合里随机取一个子集合 移除源集合元素
     *
     * @param views 源集合
     * @param max   子集合的size
     * @return
     */
    public static <T> List<T> randomListRemove(List<T> views, int max) {
        List<T> randomList = randomList(views, max);
        views.removeAll(randomList);
        return randomList;
    }

    /**
     * 清空集合
     *
     * @param collection
     */
    public static void clear(Collection<?> collection) {
        if (collection != null) {
            collection.clear();
        }
    }

    public static void clear(Map<?, ?> map) {
        if (map != null) {
            map.clear();
        }
    }

    /**
     * 内存列表分页
     *
     * @param <T>
     * @param list
     * @param startIndex
     * @param fetchCount
     * @return
     */
    public static <T> List<T> pageResult(List<T> list, int startIndex, int fetchCount) {
        if (list != null && list.size() > 0) {
            if (startIndex >= list.size()) {
                return Collections.emptyList();
            }
            startIndex = startIndex < 0 ? 0 : startIndex;
            if (fetchCount <= 0) {
                return list.subList(startIndex, list.size());
            }
            int toIndex = Math.min(startIndex + fetchCount, list.size());
            return list.subList(startIndex, toIndex);
        }
        return Collections.emptyList();
    }

    public static List<Integer> spiteByInt(String str, String splitable) {
        String[] arr = StringUtils.split(str, splitable);
        List<Integer> arrayList = New.arrayList(arr.length);
        for (int i = 0; i < arr.length; i++) {
            String element = arr[i];
            Integer number = Integer.valueOf(element);
            arrayList.add(number);
        }
        return arrayList;
    }

    /***
     * 对比两个set是否有相同值
     *
     * @param set1
     * @param set2
     * @return
     */
    public static boolean isSetEqual(Set<?> set1, Set<?> set2) {

        if (set1 == null && set2 == null) {
            return true; // Both are null
        }

        if (set1 == null || set2 == null || set1.size() == 0 || set2.size() == 0) {
            return false;
        }
        Iterator<?> ite2 = set2.iterator();

        while (ite2.hasNext()) {
            if (set1.contains(ite2.next())) {
                // 有相同值返回true
                return true;
            }
        }

        return false;
    }

    /**
     * 字符串转set 集合
     *
     * @param scaleIds
     * @return
     */
    public static Set<Long> transformStringToLong(String scaleIds, String splitable) {
        Set<Long> idSet = new HashSet<>();
        if (StringUtils.isNotBlank(scaleIds)){
            String[] split = scaleIds.split(splitable);
            for (int i = 0, size = split.length; i < size; i++) {
                if (StringUtils.isNotBlank(split[i])) {
                    idSet.add(Long.valueOf(split[i]));
                }
            }
        }
        return idSet;
    }

    public static Set<Integer> transformStringToInteger(String scaleIds, String splitable) {
        Set<Integer> idSet = new HashSet<>();
        if (StringUtils.isNotBlank(scaleIds)) {
            String[] split = scaleIds.split(splitable);
            for (int i = 0, size = split.length; i < size; i++) {
                if (StringUtils.isNotBlank(split[i])) {
                    idSet.add(Integer.valueOf(split[i]));
                }
            }
        }
        return idSet;
    }

    public static List<Integer> transformStringToIntegerList(String scaleIds, String splitable) {
        List<Integer> idList = new ArrayList<>();
        if (StringUtils.isNotBlank(scaleIds)) {
            String[] split = scaleIds.split(splitable);
            for (int i = 0, size = split.length; i < size; i++) {
                if (StringUtils.isNotBlank(split[i])) {
                    idList.add(Integer.valueOf(split[i]));
                }
            }
        }
        return idList;
    }

    public static <M, T> Map<M, T> mergeTwoMap(Map<M, T> oneMap, Map<M, T> twoMap) {
        if (MapUtils.isEmpty(oneMap)) {
            return twoMap;
        } else {
            HashMap<M, T> firstMap = new HashMap<>(oneMap);
            if (MapUtils.isNotEmpty(twoMap)) {
                HashMap<M, T> secondMap = new HashMap<>(twoMap);
                for (M index : secondMap.keySet()) {
                    firstMap.put(index, secondMap.get(index));
                }
            }
            return firstMap;
        }
    }
}
